/* 
 * Copyright (C) 2006 Sasa Coh <sasacoh@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
 */

using System.Collections.Generic;

namespace MenuDesigner
{

  #region Enums

  public enum ENumKeyTags {
    NumKey_0 = 0,
    NumKey_1,
    NumKey_2,
    NumKey_3,
    NumKey_4,
    NumKey_5,
    NumKey_6,
    NumKey_7,
    NumKey_8,
    NumKey_9,
    NumKey_star,
    NumKey_hash,  
  } 

  public enum EEditMode {
    alphanum_high,
    alphanum_low,
    numeric
  } 

  public enum EAlignment {
    justify_left,
    justify_center,
    justify_right,
  }

  #endregion Enums

  /**
   * @class CControllerFactory
   *
   * @brief 
   *
   * @author Sasa Coh
   */
  public abstract class CControllerFactory
  {
    public CComponentTimer create(VoidDelegate deleg)
    {
      return this.createTimer(deleg);
    }
    /*
    public CSynchronizer createSynchronizer()
    {
      return this.createSynchronizerImpl();
    }
    protected abstract CSynchronizer createSynchronizerImpl();
    */
    protected abstract CComponentTimer createTimer(VoidDelegate deleg);

  }

  #region Timer Handling

  /**
   * @class CComponentTimer
   *
   * @brief 
   *
   * @author Sasa Coh
   */
  public abstract class CComponentTimer
  {
	  private int mTimerId;    
    private CComponent mComponent;

    public abstract void startMillis(int timeout);

    public abstract void abort();

  }

  public class CNullTimer : CComponentTimer
  {
    private static CNullTimer _instance = null;

    public static CNullTimer getInstance()
    {
      if (_instance == null)
      { 
        _instance = new CNullTimer();
      }
      return _instance;
    }
    public override void startMillis(int timeout)
    {      
    }
    public override void abort()
    {
    }
  }

  #endregion Timer Handling
/*
  #region Synchronizer

  public abstract class CSynchronizer
  {
    public abstract void invoke(VoidIntDelegate del, int id);
  }
  #endregion Synchronizer
*/

  #region Language Handling

  public class CNullLanguage : CLanguage
  {
    public CNullLanguage()
    {
      setDefaultKeyMapping();
    }
  }

  #endregion

  #region Component Controller
  ////////////////////////////////////////////////////////////////////////////////////////////
  /**
   * @class CComponentController
   *
   * @brief 
   *
   * @author Sasa Coh
   */
  public class CComponentController
  {
    #region Variables

    private int mHomePageId = 0;

    private CPage _activePage;              //!< Current page  

    private CLanguage _language = new CNullLanguage();            //!< Current language

    private CObserver _renderer;            //!< Renderer instance

    private Stack<CPage> _history;          //!< Page history buffer

    CControllerFactory _factory = null;            //!< Component timer instance

    private Dictionary<int, CPage> _componentTable;  //!< Menu Page table

    private CInputInterface _accessif;       //!< Access interface instance

    //private CSynchronizer _synchronizer = null; 

    #endregion Variables

    #region Properties

    public CLanguage Language
    {
      set { _language = value; }
      get { return _language; }
    }

    public int HomePageId
    {
      set { mHomePageId = value; }
      get { return mHomePageId; }
    }

    public CPage Page
    {
      get
      {
        return _activePage;
      }
    }

    public CPage this [int index] 
    {
      get { return _componentTable[index]; }
    }

    public CControllerFactory Factory
    {
      get { return _factory; }
      set
      { 
        _factory = value;
        //_synchronizer = _factory.createSynchronizer();
      }
    }

    #endregion Properties

    #region Constructors
    ////////////////////////////////////////////////////////////////////////////////////////////
    // Constructor - Singleton
    private static CComponentController _instance = null;

    public static CComponentController getInstance()
    {
      if (_instance == null)
      { 
        _instance = new CComponentController();
      }
      return _instance;
    }


    private CComponentController()
    {
      CComponent.setController(this);
      
      _accessif = new CInputInterfaceImpl(this);

      _componentTable = new Dictionary<int, CPage>();

      _history = new Stack<CPage>();
    }  
    #endregion Constructors

    #region Timer Handling
    ///////////////////////////////////////////////////////////
    // Public methods for initialization
    public CComponentTimer createTimer(VoidDelegate deleg)
    {
      if (_factory != null) return _factory.create(deleg);
      return CNullTimer.getInstance();
    }
    #endregion Timer Handling

    #region Page Handling

    public void initialize()
    {
      foreach (KeyValuePair<int, CPage> pair in _componentTable)
      {
        pair.Value.onInit();
      }
    }

    public void shutdown()
    {
      _componentTable.Clear();
    }

    /*---------------------------------------
     * Attach Detach observers
     *---------------------------------------*/
    public void attach(CObserver observer) 
    {
      _renderer = observer;
    }

    /*---------------------------------------
     * Page handling methods
     *---------------------------------------*/
    public void insertPage(CPage page)
    {
      _componentTable.Add(page.Id, page);
    }

    public void removePage(CPage page)
    {
      _componentTable.Remove(page.Id);
    }

    public CPage getPage(int id)
    {
      if (_componentTable.ContainsKey(id)) return _componentTable[id];
      return null;
    }

    public int getSize()
    {
      return _componentTable.Count;
    }

    public void setActivePage(int id)
    {
      if (_activePage != null)
      {
        this.eraseComponent(_activePage);
        /*---------------------------------------
         * Clear previous component specific
         * data.
         *---------------------------------------*/
        _activePage.onExit();
      }

      // get active component from application
      _activePage = getPage(id);
      /*---------------------------------------
       * Set next component specific data.
       *---------------------------------------*/
      _activePage.onEntry();

      /*---------------------------------------
       * Put on history.
       *---------------------------------------*/
      saveHistoryEntry(_activePage);

      this.drawComponent(_activePage);
    }

    // drawing...
    public void drawComponent(CComponent component)
    {
      if (_renderer != null) component.onDraw(_renderer);
    }

    public void eraseComponent(CComponent component)
    {
      if (_renderer != null) component.onErase(_renderer);
    }

    // Page History handling
    public void showPage(int id)
    {
      if (this.getPage(id) != null) this.setActivePage(id);
      //if (this.getPage(id) != null) _synchronizer.invoke(new VoidIntDelegate(setActivePage), id);
    }

    public void refresh()
    {
      _renderer.clearScreen();
      _activePage.onEntry();
      drawComponent(_activePage);
    }

    /////////////////////////////////////////////////////////////////
    /// History
    public void previousPage()
    {
      if (_history.Count > 1) 
      {
        // pop element only if not forgetable
        if (!_activePage.isForgetable()) _history.Pop();

        showPage(_history.Peek().Id);
      }
    }

    public void clearHistory()
    {
      _history.Clear();
    }

    //<! save page in history page buffer
    protected void saveHistoryEntry(CPage entry)
    {
      if (entry.isClearHistory())
      {
        this.clearHistory();
      }

      if (entry.isForgetable())
      {
        return;
      }

      // do not add if already in history...
      if (_history.Contains(entry))
      {
        //if (_history.Peek() == entry) _history.Pop();
        return;
      }

      // check if home page then clear history
      if (this.HomePageId == entry.Id)
      {
        this.clearHistory();
      }
      _history.Push(entry);
    }
    #endregion Page Handling

    #region Language Handling
    /////////////////////////////////////////////////////////////////
    /// Language Handling 

    public string translate(string key)
    {
      return _language.getItem(key);
    }

    public char getCharacter(int id, int count, EEditMode mode )
    {
	    return _language.getCharacter(id, count, mode);
    }

    #endregion Language Handling

    #region Access Interface
    /////////////////////////////////////////////////////////////////
    // Inner class for Access Interface...
    class CInputInterfaceImpl : CInputInterface
    {
      public CInputInterfaceImpl(CComponentController refer)  
      {
        mcontroller = refer;
      }
      public bool onKeyPressed(int keyId) { return mcontroller.Page.onKeyPressed(keyId); }
      public bool onOffHookKey() { return mcontroller.Page.onOffHookKey(); }
      public bool onOnHookKey() { return mcontroller.Page.onOnHookKey(); }
      public bool onMenuKey() { return mcontroller.Page.onMenuKey(); }
      public bool onEscKey() { return mcontroller.Page.onEscKey(); }
      public bool onClearKey() { return mcontroller.Page.onClearKey(); }
      public bool onOkKey() { return mcontroller.Page.onOkKey(); }
      public bool onSpeakerKey() { return mcontroller.Page.onSpeakerKey(); }
      public bool onRedialKey() { return mcontroller.Page.onRedialKey(); }
      public bool onSoftKey(int id) { return mcontroller.Page.onSoftKey(id); }
      public bool onFunctionKey(int id) { return mcontroller.Page.onFunctionKey(id); }
      public bool onDigitKey(int id) { return mcontroller.Page.onDigitKey(id); }
      public bool onCharKey(int id) { return mcontroller.Page.onCharKey(id); }
      public bool onLeftKey() { return mcontroller.Page.onLeftKey(); }
      public bool onRightKey() { return mcontroller.Page.onRightKey(); }
      public bool onUpKey() { return mcontroller.Page.onUpKey(); }
      public bool onDownKey() { return mcontroller.Page.onDownKey(); }
      public bool onLongKey(int keyId) { return mcontroller.Page.onLongKey(keyId); }

      private CComponentController mcontroller;
    }

    // Access interface getter...
    public CInputInterface getAccessIf() {
      return _accessif;
    }
    #endregion Access Interface
  }
  #endregion Component Controller

} // namespace MenuDesigner
